home *** CD-ROM | disk | FTP | other *** search
/ .net 2002 March / DotNetMagazine-Issue107-Coverdisc-NET107-02-03-PCMac.bin / pc / PC Software / free_browsing / DavesQckSearchDbar3-14 / dqsd.exe / src / DQSDTools / MenuBuilder.cpp < prev    next >
C/C++ Source or Header  |  2002-07-08  |  14KB  |  494 lines

  1. // MenuBuilder.cpp : Implementation of CMenuBuilder
  2. #include "stdafx.h"
  3. #include "DQSDTools.h"
  4. #include "MenuBuilder.h"
  5. #include "Utilities.h"
  6.  
  7. /////////////////////////////////////////////////////////////////////////////
  8. // CMenuBuilder
  9.  
  10. LPCTSTR CMenuBuilder::DQSD_REG_KEY = _T("CLSID\\{226b64e8-dc75-4eea-a6c8-abcb4d1d37ff}");
  11. LPCTSTR CMenuBuilder::DQSD_SEC_KEY = _T("CLSID\\{226b64e8-dc75-4eea-a6c8-abcb4d1d37ff}\\SecureFiles");
  12.  
  13. #define TOOLBAR_TRACKER_WINDOW_CLASS_NAME        "DQSDMenuTrackerClass"
  14. #define TOOLBAR_TRACKER_WINDOW_NAME                "DQSDMenuTracker"
  15.  
  16. HWND        CMenuBuilder::m_hTooltipWnd;
  17.  
  18. STDMETHODIMP CMenuBuilder::SetSite(IUnknown* pUnkSite)
  19. {
  20. #if defined(DQSD_NOSECURITY) && defined(_DEBUG)
  21. #pragma message(  __FILE__ " ** WARNING! ** Compilation without security restrictions...do not distribute the resulting binary! " )
  22. #else
  23.     USES_CONVERSION;
  24.  
  25.     HRESULT hr;
  26.  
  27.     m_spUnkSite = pUnkSite;
  28.  
  29.     CComPtr<IServiceProvider> spSrvProv;
  30.     if (FAILED(hr = GetSite(IID_IServiceProvider, (void**)&spSrvProv)))
  31.         return hr;
  32.  
  33.     CComPtr<IWebBrowser2> spWebBrowser;
  34.     if (FAILED(hr = spSrvProv->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (void**)&spWebBrowser)))
  35.         return hr;
  36.  
  37.     CComBSTR bstrURL;
  38.     if (FAILED(hr = spWebBrowser->get_LocationURL(&bstrURL)))
  39.         return hr;
  40.  
  41.     HKEY hDqsdKey;
  42.     if (ERROR_SUCCESS != RegOpenKey(HKEY_CLASSES_ROOT, DQSD_SEC_KEY, &hDqsdKey))
  43.     {
  44.         Error(IDS_ERR_UNAUTHCALLER, IID_ILauncher);
  45.         return E_FAIL;
  46.     }
  47.  
  48.     
  49.     DWORD dt;
  50.     TCHAR filebuf[MAX_PATH];
  51.     DWORD filelen = sizeof(filebuf);
  52.     DWORD idw = 0;
  53.     BOOL success = FALSE;
  54.  
  55.     while (ERROR_SUCCESS == RegEnumValue(hDqsdKey, idw, filebuf, &filelen, NULL, &dt, NULL, NULL))
  56.     {
  57.         idw++;
  58.         if (URLMatchesFilename(OLE2T(bstrURL), filebuf))
  59.         {
  60.             success = TRUE;
  61.             break;
  62.         }
  63.  
  64.         filelen = sizeof(filebuf);
  65.     }
  66.  
  67.     if (success == FALSE)
  68.     {
  69.         Error(IDS_ERR_UNAUTHCALLER, IID_ILauncher);
  70.         return E_FAIL;
  71.     }
  72.  
  73. #endif
  74.  
  75.   return S_OK;
  76. }
  77.  
  78. STDMETHODIMP CMenuBuilder::Display(LPDISPATCH pDispDocument, VARIANT* pvarSelection)
  79. {
  80.     USES_CONVERSION;
  81.  
  82.     BSTR bstrSelection = NULL;
  83.     VariantInit( pvarSelection );
  84.     pvarSelection->pbstrVal = NULL;
  85.     pvarSelection->vt = VT_NULL;
  86.  
  87.     HWND hwndDQSD = UtilitiesFindDQSDWindow(pDispDocument);
  88.  
  89.     RECT rcParentWnd;
  90.     ::GetWindowRect( hwndDQSD, &rcParentWnd );
  91.  
  92.     HWND hPopupLinkedWindow;
  93.     UINT menuOptions = TPM_RETURNCMD|TPM_BOTTOMALIGN|getHorizontalPosition();
  94.     // Are we going to try tooltip tracking?
  95.     if(m_hTrackerWnd != NULL)
  96.     {
  97.         hPopupLinkedWindow = m_hTrackerWnd;
  98.     }
  99.     else
  100.     {
  101.         hPopupLinkedWindow = hwndDQSD;
  102.         menuOptions |= TPM_NONOTIFY;
  103.     }
  104.  
  105.     int nMenuX = rcParentWnd.right;
  106.     switch ( m_nHorizontalAlignment )
  107.     {
  108.     case EHorizontalAlignment::CENTER: 
  109.         nMenuX = rcParentWnd.left + ( ( rcParentWnd.right - rcParentWnd.left ) / 2 );
  110.         break;
  111.     case EHorizontalAlignment::LEFT:
  112.         nMenuX = rcParentWnd.left;
  113.         break;
  114.     case EHorizontalAlignment::RIGHT:
  115.         nMenuX = rcParentWnd.right;
  116.         break;
  117.     }
  118.  
  119.     int iMenuItem = ::TrackPopupMenuEx( m_hMain, menuOptions, nMenuX, rcParentWnd.top, hPopupLinkedWindow, NULL );
  120.     if ( iMenuItem > 0 )
  121.     {
  122.         bstrSelection = ::SysAllocString( T2CW( m_mapKeys[ iMenuItem ].c_str() ) );
  123.  
  124.         VariantInit( pvarSelection );
  125.         pvarSelection->bstrVal = bstrSelection;
  126.         pvarSelection->vt = VT_BSTR;
  127.     }
  128.  
  129.     ::DestroyMenu( m_hMain );
  130.     m_hMain = NULL;
  131.  
  132.     return S_OK;
  133. }
  134.  
  135. STDMETHODIMP CMenuBuilder::AppendMenuItem(BSTR bstrItem, BSTR bstrKey, BSTR bstrToolTip, VARIANT* pvhMenu )
  136. {
  137.     USES_CONVERSION;
  138.  
  139.     HMENU hmenu = (HMENU)m_hMain;
  140.     if (pvhMenu && ((VT_I4 == pvhMenu->vt) || (VT_I2 == pvhMenu->vt)) )
  141.     {
  142.         hmenu = pvhMenu->intVal ? (HMENU)pvhMenu->intVal : (HMENU)m_hMain;
  143.     }
  144.  
  145.     BOOL bSuccess = ::AppendMenu( hmenu, MF_STRING, ++m_nMenuItem, W2T( bstrItem ) );
  146.     if ( !bSuccess )
  147.         return E_FAIL;
  148.  
  149.     m_mapKeys[ m_nMenuItem ] = std::string( W2T( bstrKey ) );
  150.     m_toolTips[m_nMenuItem] = std::string( W2T( bstrToolTip ) );
  151.  
  152.     return S_OK;
  153. }
  154.  
  155. STDMETHODIMP CMenuBuilder::AppendSubMenu(BSTR bstrName, VARIANT* pvParentMenu, long *phmenu)
  156. {
  157.     *phmenu = (long)::CreatePopupMenu();
  158.  
  159.     USES_CONVERSION;
  160.  
  161.     HMENU hmenu = (HMENU)m_hMain;
  162.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  163.     {
  164.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  165.     }
  166.  
  167.     ::AppendMenu( hmenu, MF_POPUP, (UINT_PTR)*phmenu, W2T( bstrName ) );
  168.     
  169.     return S_OK;
  170. }
  171.  
  172. STDMETHODIMP CMenuBuilder::AppendSeparator(long hmenu)
  173. {
  174.     ::AppendMenu( (hmenu ? (HMENU)hmenu : m_hMain), MF_SEPARATOR, NULL, NULL );
  175.  
  176.     return S_OK;
  177. }
  178.  
  179. STDMETHODIMP CMenuBuilder::get_HorizontalAlignment(short *pVal)
  180. {
  181.     *pVal = (SHORT)(m_nHorizontalAlignment & 0x0000FFFF);
  182.  
  183.     return S_OK;
  184. }
  185.  
  186. STDMETHODIMP CMenuBuilder::put_HorizontalAlignment(short newVal)
  187. {
  188.     switch ( newVal )
  189.     {
  190.     case EHorizontalAlignment::CENTER:
  191.     case EHorizontalAlignment::LEFT:
  192.     case EHorizontalAlignment::RIGHT:
  193.         m_nHorizontalAlignment = newVal;
  194.         break;
  195.     default:
  196.         Error(IDS_ERR_INVALIDHORIZALIGNMENT, IID_IMenuBuilder);
  197.         return E_FAIL;
  198.     }
  199.  
  200.     return S_OK;
  201. }
  202.  
  203. UINT CMenuBuilder::getHorizontalPosition()
  204. {
  205.     switch ( m_nHorizontalAlignment )
  206.     {
  207.     case EHorizontalAlignment::CENTER: return TPM_CENTERALIGN;
  208.     case EHorizontalAlignment::LEFT: return TPM_LEFTALIGN;
  209.     case EHorizontalAlignment::RIGHT: return TPM_RIGHTALIGN;
  210.     }
  211.     return TPM_RIGHTALIGN;
  212. }
  213.  
  214. LRESULT CALLBACK CMenuBuilder::TrackerWndProc(
  215.     HWND hwnd,      // handle to window
  216.     UINT uMsg,      // message identifier
  217.     WPARAM wParam,  // first message parameter
  218.     LPARAM lParam   // second message parameter
  219.     )
  220. {
  221.     static BOOL bAdded[100];
  222.  
  223.     if(uMsg == WM_INITMENUPOPUP)
  224.     {
  225.         // It's a new popup - delete any tips
  226.         int nTools = ::SendMessage(m_hTooltipWnd, TTM_GETTOOLCOUNT, 0, 0);
  227.         ATLTRACE("Tooltips: %d existing tools\n", nTools);
  228.         for(int nTool = nTools-1; nTool >= 0; nTool--)
  229.         {
  230.             TOOLINFO ti;
  231.             ZeroMemory(&ti, sizeof(ti));
  232.             ti.cbSize = sizeof(TOOLINFO);
  233.  
  234.             if(::SendMessage(m_hTooltipWnd, TTM_ENUMTOOLS, nTool, (LPARAM)&ti))
  235.             {
  236.                 ATLTRACE("Tool %d - hWnd 0x%x, id %d\n", nTool, ti.hwnd, ti.uId);
  237.  
  238.                 ::SendMessage(m_hTooltipWnd, TTM_DELTOOL, 0, (LPARAM)&ti);
  239.  
  240.             }
  241.         }
  242.         ZeroMemory(bAdded, sizeof(bAdded));
  243.     }
  244.     if(uMsg == WM_MENUSELECT)
  245.     {
  246.         if(HIWORD(wParam) & MF_POPUP)
  247.         {
  248.             ATLTRACE("Popup - ignoring\n");
  249.         }
  250.         else
  251.         {
  252.             UINT itemId = LOWORD(wParam);
  253.             HMENU hMenu = (HMENU)lParam;
  254.             CMenuBuilder* pThis;
  255.  
  256.             pThis = (CMenuBuilder*)GetWindowLong(hwnd, GWL_USERDATA);
  257.  
  258.             // Is there a tooltip for this item?
  259.             if(pThis != NULL && pThis->m_toolTips.count(itemId) > 0)
  260.             {
  261.                 // The GetMenuItemRect call requires the zero-based position of the menu item
  262.                 // Unfortunately, I only have the ID in this message call.
  263.                 // To look up the position, I think I need to loop through the items until I find a 
  264.                 // matching ID - very clunky, but the only conversion functions seem to go
  265.                 // Pos->ID, and not the other way
  266.                 int nItems = GetMenuItemCount(hMenu);
  267.                 int nItemPosition;
  268.                 for(nItemPosition = 0; nItemPosition < nItems; nItemPosition++)
  269.                 {
  270.                     if(GetMenuItemID(hMenu, nItemPosition) == itemId)
  271.                     {
  272.                         // We've found it
  273.                         break;
  274.                     }
  275.                 }
  276.  
  277.                 // If we don't find it, nItemPosition will be == nItems, so the GetMenuItemRect call will fail
  278.                 // and we'll cope with that
  279.                 RECT itemRect;
  280.                 if(GetMenuItemRect(NULL, hMenu, nItemPosition, &itemRect))
  281.                 {
  282.  
  283.     //                ATLTRACE("ItemRect: %d,%d,%d,%d\n", itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
  284.  
  285.                     TOOLINFO ti;
  286.                     ZeroMemory(&ti, sizeof(ti));
  287.                     ti.cbSize = sizeof(ti);
  288.  
  289.                     POINT topLeft;
  290.                     topLeft.x = itemRect.left;
  291.                     topLeft.y = itemRect.top;
  292.  
  293.                     // Find the menu's window
  294.                     ti.hwnd = WindowFromPoint(topLeft);
  295.  
  296.                     ti.uFlags = TTF_TRANSPARENT;
  297.                     ti.uId = itemId;        
  298.  
  299.                     // This looks horrible, because I'm casting away the const, but it's safe
  300.                     // because I don't ask the ToolTip window to overwrite any data
  301.                     ti.lpszText = (LPTSTR)(pThis->m_toolTips[itemId].c_str());
  302.  
  303.                     MapWindowPoints(NULL, ti.hwnd, (LPPOINT)&itemRect, 2);
  304.                     ti.rect = itemRect;
  305.                     
  306. //                    ATLTRACE("ToolRect: (wnd %x) %d,%d,%d,%d\n", ti.hwnd, ti.rect.left, ti.rect.top, ti.rect.right, ti.rect.bottom);
  307.                 
  308.                     if(bAdded[nItemPosition])
  309.                     {
  310.                         ATLTRACE("Moving\n");
  311.                         ::SendMessage(m_hTooltipWnd, TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
  312.                     }
  313.                     else
  314.                     {
  315.                         ATLTRACE("Adding\n");
  316.                         if(!::SendMessage(m_hTooltipWnd, TTM_ADDTOOL, 0, (LPARAM)&ti))
  317.                         {
  318.                             ATLTRACE("AddTool failed\n");
  319.                         }
  320.                         else
  321.                         {
  322.                             bAdded[nItemPosition] = TRUE;
  323.                         }
  324.                     }
  325.  
  326.                     // Send a simulated mouse-move to the tooltip window to let it know that it should display the tip
  327.                     static MSG msgHere = { NULL,WM_MOUSEMOVE,0,0,0,0 };
  328.                     msgHere.hwnd = ti.hwnd;
  329.                     msgHere.lParam = MAKELPARAM(ti.rect.left, ti.rect.top);
  330.                     msgHere.pt.x = ti.rect.left;
  331.                     msgHere.pt.y = ti.rect.top;
  332.                     ::SendMessage(m_hTooltipWnd, TTM_RELAYEVENT, 0, (LPARAM)&msgHere);
  333.                 }
  334.             }
  335.         }
  336.     }
  337.  
  338.     return DefWindowProc(hwnd, uMsg,wParam,lParam);
  339. }
  340.  
  341.  
  342. // WGD - This was a sub-class WndProc for the tip window, while I was learning about how TTs work...
  343. /*
  344. WNDPROC lpfnOldWndProc;
  345. LONG FAR PASCAL ToolTipSubClassFunc(   HWND hWnd,
  346.                UINT uMsg,
  347.                WPARAM wParam,
  348.                LONG lParam)
  349. {
  350.  
  351.     if(uMsg == WM_PAINT)
  352.     {   
  353.         ATLTRACE("WM_PAINT\n");    
  354.     }
  355.     else if(uMsg == WM_ACTIVATE)
  356.     { 
  357.         ATLTRACE("WM_ACTIVATE\n");
  358.     }
  359.     else if(uMsg == WM_WINDOWPOSCHANGING)
  360.     {
  361.         LPWINDOWPOS pWndPos = (LPWINDOWPOS)lParam;
  362.         ATLTRACE("WM_WINDOWPOSCHANGING (%d) (%d,%d, 0x%x)\n", IsWindowVisible(hWnd), pWndPos->cx, pWndPos->cy, pWndPos->flags);
  363.     }
  364.     else if(uMsg == WM_TIMER || uMsg == WM_NCHITTEST)
  365.     { 
  366.  
  367.     }
  368.     else if(uMsg < 0x400)
  369.     {
  370.         ATLTRACE("WM_ 0x%x\n", uMsg);
  371.     }
  372.  
  373.  
  374.  
  375.     if(0) // uMsg != TTM_GETTOOLINFO)
  376.     {
  377.         ATLTRACE("ToolTipSubClassFunc - msg 0x%x\n", uMsg);
  378.  
  379.         if(uMsg == TTM_RELAYEVENT)
  380.         {
  381.             MSG* pMsg = (MSG*)lParam;
  382.  
  383. //            if(pMsg->message != WM_MOUSEMOVE)
  384.             {
  385.                 ATLTRACE("Relayed msg = 0x%x @ %d,%d\n", pMsg->message, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam));
  386.             }
  387.         }
  388.         else if(uMsg == TTM_HITTEST)
  389.         {
  390.             TTHITTESTINFO* pHti = (TTHITTESTINFO*)lParam;
  391.             BOOL bResult = CallWindowProc(lpfnOldWndProc, hWnd, uMsg, wParam, lParam);
  392.             ATLTRACE("Hittest %d,%d, result %d\n", pHti->pt.x, pHti->pt.y, bResult);
  393.             return bResult;
  394.         }
  395.         else if(uMsg == TTM_WINDOWFROMPOINT)
  396.         {
  397.             POINT* pPoint = (POINT*)lParam;
  398.             HANDLE result = (HANDLE)CallWindowProc(lpfnOldWndProc, hWnd, uMsg, wParam, lParam);
  399.             ATLTRACE("WndFromPoint %d,%d, result 0x%x\n", pPoint->x, pPoint->y, result);
  400.             if(pPoint->x == 0 && pPoint->y == 0)
  401.             {
  402.                 return 0;
  403.             }
  404.             return (LONG)result;
  405.         }
  406.         
  407.     }
  408.  
  409.     return CallWindowProc(lpfnOldWndProc, hWnd, uMsg, wParam, lParam);
  410.  
  411. }
  412. */
  413.  
  414. // Set up the tracking window which can follow the menu position and display tooltips
  415. STDMETHODIMP CMenuBuilder::InitialiseTooltips(long displayTimeMultiplier)
  416. {
  417.     // Create a window which we use to receive menu tracking info
  418.     WNDCLASS wc;
  419.     ZeroMemory(&wc, sizeof(wc));
  420.     wc.lpfnWndProc = TrackerWndProc;
  421.     wc.lpszClassName = TOOLBAR_TRACKER_WINDOW_CLASS_NAME;
  422.  
  423.     HWND hExistingWindow = FindWindow(wc.lpszClassName, TOOLBAR_TRACKER_WINDOW_NAME);
  424.     if(hExistingWindow != NULL)
  425.     {
  426.         // THere's already hotkey window
  427.         ATLTRACE("MenuTracker - window exists\n");
  428.         DestroyWindow(hExistingWindow);
  429.     }
  430.  
  431.     RegisterClass(&wc);
  432.  
  433.     // Create the menu tracking window
  434.     m_hTrackerWnd = CreateWindow(wc.lpszClassName, TOOLBAR_TRACKER_WINDOW_NAME, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
  435.     if(m_hTrackerWnd == NULL)
  436.     {
  437.         ATLTRACE("Failed to create a window for MenuTracker (err %d)\n", GetLastError());
  438.         return Error(IDS_ERR_MENU_TRACKER_WINDOW_FAILED, IID_ILauncher, E_FAIL);
  439.     }
  440.  
  441.     // Store a 'this' pointer on the tracker window
  442.     ::SetWindowLong(m_hTrackerWnd, GWL_USERDATA, (LONG)this);
  443.  
  444.     // Create a tooltip window
  445.     if(m_hTooltipWnd != NULL)
  446.     {
  447.         DestroyWindow(m_hTooltipWnd);
  448.     }
  449.  
  450.     m_hTooltipWnd = CreateWindow(TOOLTIPS_CLASS,
  451.         NULL,
  452.         TTS_NOPREFIX | TTS_ALWAYSTIP,         
  453.         CW_USEDEFAULT,
  454.         CW_USEDEFAULT,
  455.         CW_USEDEFAULT,
  456.         CW_USEDEFAULT,
  457.         NULL,
  458.         NULL,
  459.         _Module.GetModuleInstance(),
  460.         NULL
  461.         );
  462.     if(m_hTooltipWnd == NULL)
  463.     {
  464.         return Error(_T("Failed to create tooltip window"), IID_ILauncher, E_FAIL);
  465.     }
  466.  
  467.     ::SetWindowPos(m_hTooltipWnd,
  468.         HWND_TOPMOST,
  469.         0,
  470.         0,
  471.         0,
  472.         0,
  473.         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
  474.  
  475.     RECT tipMargin = { 5,5,5,5 };
  476.     ::SendMessage(m_hTooltipWnd, TTM_SETMARGIN, 0, (LPARAM)&tipMargin);
  477.  
  478.     // Set a maximum width - this enables multi-line tooltips
  479.     RECT workArea;
  480.     SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&workArea, 0);
  481.     ::SendMessage(m_hTooltipWnd, TTM_SETMAXTIPWIDTH, 0, (workArea.right-workArea.left)/3);
  482.  
  483.     // Set the tool tip time multiplier
  484.     // (GetDoubleClickTime()*10 is the system default)
  485.     ATLTRACE("InitToolTips: DisplayTimeMult %d\n", displayTimeMultiplier);
  486.     displayTimeMultiplier = max(1, displayTimeMultiplier);
  487.     ::SendMessage(m_hTooltipWnd, TTM_SETDELAYTIME, TTDT_AUTOPOP, GetDoubleClickTime()*10*displayTimeMultiplier);
  488.  
  489. // Subclass the tooltip window - just for debugging
  490. //    lpfnOldWndProc = (WNDPROC)SetWindowLong(m_hTooltipWnd, GWL_WNDPROC, (DWORD)ToolTipSubClassFunc);
  491.  
  492.     return S_OK;
  493. }
  494.